terraform创建华为云、AWS资源

前言

目前IT设备对于大多数企业公司来说是必不可少的基础设施,由于云计算的按需付费,便捷配置计算资源(资源包括网络,服务器,存储,应用软件,服务)的特点很受企业的欢迎,因此大多数企业都从传统的IDC迁移到云平台,或者直接到云平台上搭建自己的业务。然而云计算平台很多家,国外有云计算鼻祖亚马AWS,还有微软的Azure,Google的GCP,国内而言比较有名的,阿里巴巴的Alicloud,腾讯的TencentCloud,华为的HuaweiCloud。

在运维领域中,针对这些云平台的IT资源管理也是重中之重。尤其是最近几逐渐流行的DevOps理念,Infrastructure as Code(基础架构即代码)文化,所以在社区的贡献下,Terraform这个工具应用而生,Terraform是来自HashiCorp家族,因此采用了 HashiCorp 配置语言 (HCL),Terraform的意义在于,通过同一套规则和命令来操作不同的云平台(包括私有云)。详情可参考官方文档https://www.terraform.io

参考:

https://bbs.huaweicloud.com/blogs/86505eb5eefa11e8bd5a7ca23e93a891

https://www.jianshu.com/p/d0035b7c3801

https://www.linode.com/docs/applications/configuration-management/create-terraform-module/

安装terraform

以下是官方安装教程https://www.terraform.io/intro/getting-started/install.html,下载解压,配置环境变量即可。以下是我的环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[centos@ip-10-20-6-165 ~]$ uname -r
3.10.0-514.26.2.el7.x86_64
[centos@ip-10-20-6-165 ~]$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
[centos@ip-10-20-6-165 ~]$ ll /opt/terraform*
-rwxrwxr-x 1 centos centos 69122624 Apr 10 2018 /opt/terraform
-rw-r--r-- 1 root root 16490308 Apr 10 2018 /opt/terraform_0.11.7_linux_amd64.zip
[centos@ip-10-20-6-165 ~]$ grep opt /etc/profile
export PATH=$PATH:/opt
[centos@ip-10-20-6-165 ~]$ which terraform
/opt/terraform

[centos@ip-10-20-6-165 ~]$ terraform --version
Terraform v0.11.7
Your version of Terraform is out of date! The latest version
is 0.11.9. You can update by downloading from www.terraform.io/downloads.html

编写配置

目录配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
terraform_scripts/
├── main.tf #主执行文件
├── outputs.tf #定义输出变量
├── secrets.tfvars #.....
├── terraform #.....
├── terraform.tfvars #直接定义变量文件(变量需要在variables.tf事先定义)
├── variables.tf #变量文件
└── modules/ #模块
    ├── network/
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    └── instance/
        ├── main.tf
        ├── variables.tf
        └── outputs.tf

模块化脚本(华为云)

network模块

network/variables.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
variable "vpc_name" {

}
variable "vpc_cidr" {
default = "192.168.0.0/16"
}
variable "subnet_name" {

}
variable "subnet_dir" {
default = "192.168.2.0/24"
}
variable "subnet_gateway_ip" {
default = "192.168.2.1"
}
variable "secgroup_name" {

}

network/outputs.tf

1
2
3
4
5
6
output "vpc_id" {
value = "${huaweicloud_vpc_v1.vpc.id}"
}
output "secgroup_1_name" {
value = "${huaweicloud_networking_secgroup_v2.secgroup_1.name}"
}

network/main.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#-----VPC
resource "huaweicloud_vpc_v1" "vpc" {
name = "${var.vpc_name}"
cidr = "${var.vpc_cidr}"
}

#----subnet-----
resource "huaweicloud_vpc_subnet_v1" "subnet" {
name = "${var.subnet_name}"
cidr = "${var.subnet_cidr}"
gateway_ip = "${var.subnet_gateway_ip}"
vpc_id = "${huaweicloud_vpc_v1.vpc.id}"
}

#----secgroup
resource "huaweicloud_networking_secgroup_v2" "secgroup_1" {
name = "${var.secgroup_name}"
}

instance模块

instance/variables.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
variable "instance_sg" {

}
variable "instance_name" {

}
variable "instance_az" {
default = "cn-east-2b"
}
vaiable "instance_image_id" {
default = "9526f9b7-423c-4fdc-92ad-f1630a524652"
description = "CentOS7.6 64bit"
}
variable "instance_flavor_name" {
default = "s3.small.1"
}
variable "instance_network_id" {

}
variable "instance_admin_pass" {
}

instance/outputs.tf

1
2


instance/main.tf

1
2
3
4
5
6
7
8
9
10
11
12
#-----ECS
resources "huaweicloud_compute_instance_v2" "instance" {
availability_zone = "${var.instance_az}"
name = "${var.instance_name}"
image_id = "${var.instance_image_id}"
flavor_name = "${var.instance_flavor_name}"
security_groups = "${var.instance_sg}"
admin_pass = "${var.instance_admin_pass}"
network {
name = "${var.instance_network_id}" #not sure, maybe should be uuid
}
}

主执行文件

variables.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
variable "secret_key" {

}
variable "access_key" {

}
variable "region" {
default = "cn-east-2"
description = "string"
}
variable "env" {

}

terraform.tfvars

1
2
3
secret_key = "string"
access_key = "string"
env = "test"

main.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#---provider
provider "huaweicloud" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
tenant_name = "tenant"
region = "${var.region}"
auth_url = "https://iam.myhwclouds.com:443/v3"
}
module "network" {
source = "./modules/network"
vpc_name = "vpc-${var.env}"
subnet_name = "subnet-${var.env}"
secgroup_name = "sg-${var.env}"
}
module "instance" {
source = "./modules/instance"
instance_name = "test"
instance_flavor_name = "s3.small.1"
instance_security_group = "${modules.network.secgroup_name}"
instance_network_id = "${modules.network.vpc_id}"
instance_admin_pass "${var.admin_pass}"
}

AWS基本使用脚本(非模块化)

目录结构

1
2
3
4
5
6
7
8
9
[centos@ip-10-20-6-165 stg_cn_rubin]$ ll
total 32
-rw-rw-r-- 1 centos centos 285 Sep 21 07:24 backend.tf
-rw-rw-r-- 1 centos centos 1723 Sep 25 07:54 bastion.tf
-rw-rw-r-- 1 centos centos 977 Sep 25 08:10 common.tf
-rw-rw-r-- 1 centos centos 593 Sep 25 09:27 outputs.tf
-rw-rw-r-- 1 centos centos 173 Sep 21 07:24 terraform.tfvars
-rw-rw-r-- 1 centos centos 901 Sep 25 09:48 variables.tf
-rw-rw-r-- 1 centos centos 6676 Oct 20 03:09 vpc.tf

backend.tf

这个文件是定义provider和远程存储terraform.tfstate的s3存储桶,provider是Terraform定制的一套接口,阿里云、AWS、私有云等如果想接入进来被Terraform编排和管理就要实现一套Provider,官网https://www.terraform.io/docs/providers/index.html,我使用的AWS的云平台,所以使用的AWS的provider。

关于terraform.tfstate,我在前言中说过,状态文件是记录当前资源的状态。每次运行terraform apply时,都会把最新的配置和当前状态文件中的内容进行比较后,再做更改。所以这个文件不能乱改,团队协作时可以加个锁,因此手动通过AWS console添加了一个存储桶,然后再加了一个dynamodb_table的锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[centos@ip-10-20-6-165 stg_cn_rubin]$ cat backend.tf
provider "aws" {
region = "${var.aws_region}" # 引用了变量,变量值在variables.tf中
}

terraform {
required_version = ">= 0.11.7"
backend "s3" {
encrypt = "true"
bucket = "rubin-cn-stg-terraform-state"
region = "cn-north-1"
key = "vpc/stg_cn_rubin/terraform.tfstate"
dynamodb_table = "terraform-lock"
}
}

variables.tf

这个文件相当于申明了variable,可以在此加一个默认的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
[centos@ip-10-20-6-165 stg_cn_rubin]$ cat variables.tf
variable "aws_region" {
default = "cn-north-1"
}

variable "vpc_name" {
description = "The name of the VPC"
}

variable "cidr_numeral" {
description = "The VPC CIDR numeral (10.x.0.0/16)"
}

variable "cidr_numeral_public" {
default = {
"0" = "0"
"1" = "1"
"2" = "2"
}
}

variable "cidr_numeral_private" {
default = {
"0" = "3"
"1" = "4"
"2" = "5"
}
}

variable "cidr_numeral_private_db" {
default = {
"0" = "6"
"1" = "7"
"2" = "8"
}
}

variable "cidr_numeral_private_emr" {
default = {
"0" = "9"
"1" = "10"
"2" = "11"
}
}

variable "ssh_key_name" {
description = "A master ssh key"
}

variable "bastion_image" {
default = {
cn-north-1 = "ami-7866b115"
}
}

variable "env" {
description = "The AWS env tag"
}

variable "availability_zones" {
description = "A comma-delimited list of availability zones for the VPC."
}

terraform.tfvars

此文件是在文件申明的变量赋值,赋值可以供当前目录的其他的文件引用

1
2
3
4
5
6
7
[centos@ip-10-20-6-165 stg_cn_rubin]$ cat terraform.tfvars
aws_region = "cn-north-1"
cidr_numeral = "101"
vpc_name = "rubin_stg_cn"
ssh_key_name = "rubin-stg-cn-master"
env = "staging"
availability_zones = "cn-north-1a,cn-north-1b"

vpc.tf

这个文件就是主文件,用来建立VPC,subnet,gateway,natgateway,路由表,路由表关联等一系列操作。其中有些是Terraform的内部函数,关于内部函数可参考https://www.terraform.io/docs/configuration/interpolation.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
[centos@ip-10-20-6-165 stg_cn_rubin]$ cat vpc.tf 
# VPC DESIGN

resource "aws_vpc" "default" {
cidr_block = "10.${var.cidr_numeral}.0.0/16"
enable_dns_hostnames = true

tags {
Name = "vpc-${var.vpc_name}"
}
}

resource "aws_internet_gateway" "default" {
vpc_id = "${aws_vpc.default.id}"

tags {
Name = "igw-${var.vpc_name}"
}
}

resource "aws_eip" "nat" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc = true

tags {
Name = "ip-NAT-${var.vpc_name}"
}
}

resource "aws_nat_gateway" "nat" {
count = "${length(split(",", "${var.availability_zones}"))}"

allocation_id = "${element(aws_eip.nat.*.id, count.index)}"
subnet_id = "${element(aws_subnet.public.*.id, count.index)}"

tags {
Name = "gw-NAT-${var.vpc_name}"
}
}


# PUBLIC SUBNETS
# The public subnet is where the bastion, NATs and ELBs reside. In most cases,
# there should not be any servers in the public subnet.

resource "aws_subnet" "public" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc_id = "${aws_vpc.default.id}"

cidr_block = "10.${var.cidr_numeral}.${lookup(var.cidr_numeral_public, count.index)}.0/24"
availability_zone = "${element(split(",", var.availability_zones), count.index)}"
map_public_ip_on_launch = true

tags {
Name = "public${count.index}-${var.vpc_name}"
immutable_metadata = "{ \"purpose\": \"external_${var.vpc_name}\", \"target\": null }"
}
}

# PUBLIC SUBNETS - Default route
#
resource "aws_route_table" "public" {
vpc_id = "${aws_vpc.default.id}"

route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.default.id}"
}

tags {
Name = "publicrt-${var.vpc_name}"
}
}

# PUBLIC SUBNETS - Route associations
#
resource "aws_route_table_association" "public" {
count = "${length(split(",", "${var.availability_zones}"))}"
subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
route_table_id = "${aws_route_table.public.id}"
}

# PRIVATE SUBNETS
#
# Route Tables in a private subnet will not have Route resources created
# statically for them as the NAT instances are responsible for dynamically
# managing them on a per-AZ level using the Network=Private tag.

resource "aws_subnet" "private" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc_id = "${aws_vpc.default.id}"

cidr_block = "10.${var.cidr_numeral}.${lookup(var.cidr_numeral_private, count.index)}.0/24"
availability_zone = "${element(split(",", var.availability_zones), count.index)}"

tags {
Name = "private${count.index}-${var.vpc_name}"
immutable_metadata = "{ \"purpose\": \"internal_${var.vpc_name}\", \"target\": null }"
Network = "Private"
}
}

resource "aws_route_table" "private" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc_id = "${aws_vpc.default.id}"

route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = "${element(aws_nat_gateway.nat.*.id, count.index)}"
}

tags {
Name = "private${count.index}rt-${var.vpc_name}"
Network = "Private"
}
}

resource "aws_route_table_association" "private" {
count = "${length(split(",", "${var.availability_zones}"))}"
subnet_id = "${element(aws_subnet.private.*.id, count.index)}"
route_table_id = "${element(aws_route_table.private.*.id, count.index)}"
}

# PRIVATE SUBNETS (DB)
#
# Route Tables in a private subnet will not have Route resources created
# statically for them as the NAT instances are responsible for dynamically
# managing them on a per-AZ level using the Network=Private tag.

resource "aws_subnet" "private_db" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc_id = "${aws_vpc.default.id}"

cidr_block = "10.${var.cidr_numeral}.${lookup(var.cidr_numeral_private_db, count.index)}.0/24"
availability_zone = "${element(split(",", var.availability_zones), count.index)}"

tags {
Name = "db-private${count.index}-${var.vpc_name}"
immutable_metadata = "{ \"purpose\": \"internal_${var.vpc_name}\", \"target\": null }"
Network = "Private"
}
}

resource "aws_route_table" "private_db" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc_id = "${aws_vpc.default.id}"

route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = "${element(aws_nat_gateway.nat.*.id, count.index)}"
}

tags {
Name = "privatedb${count.index}rt-${var.vpc_name}"
Network = "Private"
}
}

resource "aws_route_table_association" "private_db" {
count = "${length(split(",", "${var.availability_zones}"))}"
subnet_id = "${element(aws_subnet.private_db.*.id, count.index)}"
route_table_id = "${element(aws_route_table.private_db.*.id, count.index)}"
}


# PRIVATE SUBNETS
#
# Route Tables in a private subnet will not have Route resources created
# statically for them as the NAT instances are responsible for dynamically
# managing them on a per-AZ level using the Network=Private tag.

resource "aws_subnet" "private_emr" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc_id = "${aws_vpc.default.id}"

cidr_block = "10.${var.cidr_numeral}.${lookup(var.cidr_numeral_private_emr, count.index)}.0/24"
availability_zone = "${element(split(",", var.availability_zones), count.index)}"

tags {
Name = "private_emr${count.index}-${var.vpc_name}"
immutable_metadata = "{ \"purpose\": \"internal_${var.vpc_name}\", \"target\": null }"
Network = "Private"
}
}

resource "aws_route_table" "private_emr" {
count = "${length(split(",", "${var.availability_zones}"))}"
vpc_id = "${aws_vpc.default.id}"

route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = "${element(aws_nat_gateway.nat.*.id, count.index)}"
}

tags {
Name = "private_emr${count.index}rt-${var.vpc_name}"
Network = "Private"
}
}

resource "aws_route_table_association" "private_emr" {
count = "${length(split(",", "${var.availability_zones}"))}"
subnet_id = "${element(aws_subnet.private_emr.*.id, count.index)}"
route_table_id = "${element(aws_route_table.private_emr.*.id, count.index)}"
}

outputs.tf

当我们创建的资源后,经常需要知道这些资源的ID,因此定义一个output,将我们想要的资源ID显示出来或者输出到文件,从而避免我们在去控制台上查询获取这些信息。Terraform的出参就像是存过的产出,开发人员可以在编排时定义output出参来指定自己关心的内容,该内容会在任务执行的日志中高亮显示,而且在任务执行完毕后我们可以通过terrafomr output var_name的方式查看参数结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[centos@ip-10-20-6-165 stg_cn_rubin]$ cat outputs.tf 
output "vpc_id" {
value = "${aws_vpc.default.id}"
}

output "cidr_block" {
value = "${aws_vpc.default.cidr_block}"
}

output "private_subnets" {
value = "${join(",", aws_subnet.private.*.id)}"
}

output "public_subnets" {
value = "${join(",", aws_subnet.public.*.id)}"
}

output "private_db_subnets" {
value = "${join(",", aws_subnet.private_db.*.id)}"
}

output "private_emr_subnets" {
value = "${join(",", aws_subnet.private_emr.*.id)}"
}

output "nat_eip" {
value = "${join(",", aws_eip.nat.*.public_ip)}"
}

output "bastion_eip" {
value = "${aws_eip.bastion.public_ip}"
}

bastion.tf

当VPC建立好的时候,我们只需要通过一台有公网IP的跳板机,去访问私网的机器,这个文件就是创建一个跳板机的安全组,能通过IP(1...*/28 )访问跳板机的22,2022端口,80,443,53,123端口流量能出,通过安全组限制网络进出流量。安全起见,我对其中IP加密显示,可以自行更改。更严格的还可以通过VPC配置的Network ACLs去控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
[centos@ip-10-20-6-165 stg_cn_rubin]$ cat bastion.tf 
resource "aws_security_group" "bastion" {
name = "bastion-${var.vpc_name}"
description = "Allows SSH access to the bastion server"

vpc_id = "${aws_vpc.default.id}"

ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["1.*.*.*/28"]
description = "Office IP"
}

ingress {
from_port = 2022
to_port = 2022
protocol = "tcp"
cidr_blocks = ["1.*.*.*/28"]
description = "Office IP"
}

egress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 53
to_port = 53
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 53
to_port = 53
protocol = "udp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 123
to_port = 123
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 123
to_port = 123
protocol = "udp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["10.0.0.0/8"]
}

tags {
Name = "bastion-${var.vpc_name}"
}
}

# EIP for bastion
resource "aws_eip" "bastion" {
vpc = true
}

common.tf

这个文件是创建了一个共有的安全组给私网地址的机器使用。能接受当前VPC下私网10.0.0.0/8网段的任何流量,流量能从80,443,53,123的端口出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[centos@ip-10-20-6-165 stg_cn_rubin]$ cat common.tf 
resource "aws_security_group" "internal_common" {
name = "internal_common-${var.vpc_name}"
description = "commonly used security group for ocf instances"

vpc_id = "${aws_vpc.default.id}"

ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["10.0.0.0/8"]
}

egress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress { # dns
from_port = 53
to_port = 53
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress { # dns
from_port = 53
to_port = 53
protocol = "udp"
cidr_blocks = ["0.0.0.0/0"]
}
egress { # ntp
from_port = 123
to_port = 123
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress { # ntp
from_port = 123
to_port = 123
protocol = "udp"
cidr_blocks = ["0.0.0.0/0"]
}
}

AWS key

创建Access key 参考官网https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html
配置Access key 参考官网https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/cli-chap-getting-started.html

1
2
3
4
5
6
7
8
9
10
11
12
13
[centos@ip-10-20-6-165 ~]$ aws configure --profile rubin-stg
AWS Access Key ID [****************M67J]:
AWS Secret Access Key [****************mgNp]:
Default region name [cn-north-1]:
Default output format [json]:
[centos@ip-10-20-6-165 ~]$ sed -n '24,26p' /home/centos/.aws/config
[profile rubin-stg]
output = json
region = cn-north-1
[centos@ip-10-20-6-165 ~]$ sed -n '25,27p' /home/centos/.aws/credentials
[rubin-stg]
aws_access_key_id = ****************M67J
aws_secret_access_key = ****************mgNp

创建资源

Terrform get & init

执行terraform init命令,就像git init一样,对当前目录做初始化,下载tf中的provider,并为后续的操作准备必要的环境条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
[centos@ip-10-20-6-165 ~]$ cd rubin/terraform/vpc/stg_cn_rubin/
[centos@ip-10-20-6-165 stg_cn_rubin]$ pwd
/home/centos/rubin/terraform/vpc/stg_cn_rubin
[centos@ip-10-20-6-165 stg_cn_rubin]$ export AWS_DEFAULT_PROFILE=rubin-stg && export AWS_PROFILE=rubin-stg
[centos@ip-10-20-6-165 stg_cn_rubin]$ terraform --help
Usage: terraform [--version] [--help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
apply Builds or changes infrastructure
console Interactive console for Terraform interpolations
destroy Destroy Terraform-managed infrastructure
env Workspace management
fmt Rewrites config files to canonical format
get Download and install modules for the configuration
graph Create a visual graph of Terraform resources
import Import existing infrastructure into Terraform
init Initialize a Terraform working directory
output Read an output from a state file
plan Generate and show an execution plan
providers Prints a tree of the providers used in the configuration
push Upload this Terraform module to Atlas to run
refresh Update local state file against real resources
show Inspect Terraform state or plan
taint Manually mark a resource for recreation
untaint Manually unmark a resource as tainted
validate Validates the Terraform files
version Prints the Terraform version
workspace Workspace management

All other commands:
debug Debug output management (experimental)
force-unlock Manually unlock the terraform state
state Advanced state management


[centos@ip-10-20-6-165 stg_cn_rubin]$ terraform get #编写配置文件中没有导入module,所以执行没有结果,如果配置文件有导入module应先执行


[centos@ip-10-20-6-165 stg_cn_rubin]$ terraform init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "aws" (1.41.0)...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 1.41"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Terraform plan

预览执行计划,不是必须,可以预览要创建的资源,终端日志太长,只粘贴一部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
[centos@ip-10-20-6-165 stg_cn_rubin]$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

+ aws_eip.bastion
id: <computed>
allocation_id: <computed>
association_id: <computed>
domain: <computed>
instance: <computed>
network_interface: <computed>
private_ip: <computed>
public_ip: <computed>
vpc: "true"

+ aws_eip.nat[0]
id: <computed>
allocation_id: <computed>
association_id: <computed>
domain: <computed>
instance: <computed>
network_interface: <computed>
private_ip: <computed>
public_ip: <computed>
tags.%: "1"
tags.Name: "ip-NAT-rubin_stg_cn"
vpc: "true"

+ aws_eip.nat[1]
id: <computed>
allocation_id: <computed>
association_id: <computed>
domain: <computed>
...

+ aws_subnet.public[1]
id: <computed>
arn: <computed>
assign_ipv6_address_on_creation: "false"
availability_zone: "cn-north-1b"
cidr_block: "10.101.1.0/24"
ipv6_cidr_block: <computed>
ipv6_cidr_block_association_id: <computed>
map_public_ip_on_launch: "true"
tags.%: "2"
tags.Name: "public1-rubin_stg_cn"
tags.immutable_metadata: "{ \"purpose\": \"external_rubin_stg_cn\", \"target\": null }"
vpc_id: "${aws_vpc.default.id}"

+ aws_vpc.default
id: <computed>
arn: <computed>
assign_generated_ipv6_cidr_block: "false"
cidr_block: "10.101.0.0/16"
default_network_acl_id: <computed>
default_route_table_id: <computed>
default_security_group_id: <computed>
dhcp_options_id: <computed>
enable_classiclink: <computed>
enable_classiclink_dns_support: <computed>
enable_dns_hostnames: "true"
enable_dns_support: "true"
instance_tenancy: "default"
ipv6_association_id: <computed>
ipv6_cidr_block: <computed>
main_route_table_id: <computed>
tags.%: "1"
tags.Name: "vpc-rubin_stg_cn"


Plan: 32 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Terraform apply

真正执行编排计划,创建资源的终端日志太长,只粘贴一部分,几分钟后整个资源全被创建完成,最后output把当前资源的ID显示出来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
[centos@ip-10-20-6-165 stg_cn_rubin]$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

+ aws_eip.bastion
id: <computed>
allocation_id: <computed>
association_id: <computed>

...

tags.Name: "vpc-rubin_stg_cn"


Plan: 32 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.

Enter a value: yes
aws_vpc.default: Creating...
arn: "" => "<computed>"
assign_generated_ipv6_cidr_block: "" => "false"
cidr_block: "" => "10.101.0.0/16"
default_network_acl_id: "" => "<computed>"
default_route_table_id: "" => "<computed>"

...

aws_route_table_association.private[0]: Creation complete after 0s (ID: rtbassoc-0dec0c6caa85081aa)
aws_route_table_association.private[1]: Creation complete after 0s (ID: rtbassoc-00541f1193c1f006a)
aws_route_table_association.private_db[0]: Creation complete after 0s (ID: rtbassoc-0707dc991b6f0b502)
aws_route_table_association.private_db[1]: Creation complete after 0s (ID: rtbassoc-0e1c00b46b31e13a6)
aws_route_table_association.private_emr[1]: Creation complete after 0s (ID: rtbassoc-0dcfc3ec369382fa4)
aws_route_table_association.private_emr[0]: Creation complete after 0s (ID: rtbassoc-0ed91fcc9955b3674)

Apply complete! Resources: 32 added, 0 changed, 0 destroyed.

Outputs:

bastion_eip = 54.223.216.43
cidr_block = 10.101.0.0/16
nat_eip = 54.222.176.3,54.222.249.234
private_db_subnets = subnet-095f9065be2e9bb6d,subnet-0d9fdec0b255f17c1
private_emr_subnets = subnet-090653a4e725b8d90,subnet-0d0fd140f10721f60
private_subnets = subnet-0f34c39ec475c0384,subnet-095341650c1b43695
public_subnets = subnet-06bb6bea3d757253b,subnet-03307ab8f793fd944
vpc_id = vpc-02d9520415468c7f0
--------------------本文结束,感谢您的阅读--------------------

本文标题:terraform创建华为云、AWS资源

文章作者:弓昭

发布时间:2019年06月03日 - 22:12

最后更新:2020年04月08日 - 22:20

原始链接:https://gongzhao1.gitee.io/terraform创建华为云 AWS资源/

联系邮箱:gongzhao1@foxmail.com